#ifndef _NE_MATH_H_
#define _NE_MATH_H_

#include <neinit.h>

namespace ne
{
    class NEAPI Math
    {
        public:
            /*
                std::abs
                std::acos
                std::asin
                std::atan
                std::atan2
                std::ceil
                std::cos
                std::cosh
                std::exp
                std::fabs
                std::floor
                std::fmod
                std::frexp
                std::ldexp
                std::log
                std::log10
                std::modf
                std::pow
                std::sin
                std::sinh
                std::sqrt
                std::tan
                std::tanh
            */

            inline static bool Equal(const real value, const real keyValue, const real tolerance=EPSILON)
            {
                if (std::abs(value - keyValue) <= tolerance)
                {
                    return true;
                }
                return false;
            }

            inline static void Clamp(real &value, const real minValue=0.0f, const real maxValue=1.0f)
            {
                if (value < minValue)
                {
                    value = minValue;
                }
                else if (value > maxValue)
                {
                    value = maxValue;
                }
            }

            inline static real Clamp(const real &value, const real minValue=0.0f, const real maxValue=1.0f)
            {
                real temp = value;
                if (temp < minValue)
                {
                    temp = minValue;
                }
                else if (temp > maxValue)
                {
                    temp = maxValue;
                }
                return temp;
            }

            inline static int Round(const real &value)
            {
                if (value > 0.0f)
                {
                    return int(value + 0.5f);
                }
                else
                {
                    return int(value - 0.5f);
                }
            }

            inline static real Lerp(const real vS, const real vD, const real u)
            {
                return vS + (vD - vS) * u;
            }

            inline static real Angle(const real radian)
            {
                return INVERTED_PI * radian * HALF_CIRCLE;
            }

            inline static real Radian(const real angle)
            {
                return PI * angle / HALF_CIRCLE;
            }

            inline static uint16_t Endian(const uint16_t v)
            {
                return ((v & 0xFF) << 8) | ((v & 0xFF00) >> 8);
            }

            inline static uint32_t Endian(const uint32_t v)
            {
                return ((v & 0xFF) << 24) |
                       ((v & 0xFF00) << 8) |
                       ((v & 0xFF0000) >> 8) |
                       ((v & 0xFF000000) >> 24);
            }

        public:
            static const real QUARTER_PI;
            static const real HALF_PI;
            static const real PI;
            static const real DOUBLE_PI;
            static const real INVERTED_PI;      // 1/PI
            static const real QUARTER_CIRCLE;
            static const real HALF_CIRCLE;
            static const real CIRCLE;

            static const real E;
            static const real LOG2E;            // log2(e)
            static const real LOG10E;           // log10(e)
            static const real LN2;              // ln(2)
            static const real LN10;             // ln(10)

            static const real SQRT2;            // sqrt(2)
            static const real INVERTED_SQRT2;   // 1/sqrt(2)

            static const real EPSILON;
            static const real EPSILON2;         // EPSILON * EPSILON
            static const real POS_HUGE_VAL;
            static const real NEG_HUGE_VAL;
    };
}

#endif
